<?php


namespace wchat\qq\pay;


use Exception;
use wchat\common\Help;
use wchat\common\Result;
use wchat\qq\SmallProgram;

/**
 * Class Enterprise_payment
 * @package wchat\qq\pay
 */
class Enterprise_payment extends SmallProgram
{
    public string $_cash = '/cgi-bin/epay/qpay_epay_b2c.cgi';

    private array $_errors = [
        'SYSTEMERROR'              => '系统错误',
        'PARAM_ERROR'              => '请求参数未按指引进行填写',
        'SIGNERROR'                => '参数签名结果不正确',
        'OP_USER_PASSWD_ERROR'     => '操作员密码校验失败',
        'OP_USER_AUTH_ERROR'       => '操作员权限错误',
        'TRANSFER_FEE_LIMIT_ERROR' => '转账限额错误',
        'TRANSFER_FAIL'            => '收款用户的账户不支持收款，收款失败',
        'NOTENOUGH'                => '商户营销账户的余额不足',
        'ORDERNOTEXIST'            => '转账订单不存在',
        'APPID_OR_OPENID_ERR'      => 'appid 或 openid 非法',
        'TOTAL_FEE_OUT_OF_LIMIT'   => '单笔限额检查失败',
        'SPID_NOT_ALLOW'           => '当前商户不支持企业付款',
        'REALNAME_CHECK_ERROR'     => '实名检查失败',
        'RE_USER_NAME_CHECK_ERROR' => '用户真实姓名校验失败',
        'INVALID_CERTIFICATE'      => '证书非法',
    ];

    private array $_requestParams = [];

    /**
     * @param string $value
     */
    public function setOpUserId(string $value): void
    {
        $this->_requestParams['op_user_id'] = $value;
    }

    /**
     * @param string $value
     */
    public function setOpUserPassword(string $value): void
    {
        $this->_requestParams['op_user_passwd'] = $value;
    }

    /**
     * @param string $value
     */
    public function setSpbillCreateIp(string $value): void
    {
        $this->_requestParams['spbill_create_ip'] = $value;
    }

    /**
     * @param string $mch_billno
     * @param string $openId
     * @param float $price
     * @return Result
     */
    public function mch_send(string $mch_billno, string $openId, float $price): Result
    {
        $client = $this->createClient($this->_cash, $this->orderConfig($mch_billno, $openId, $price));
        if (!in_array($client->getStatusCode(), [101, 200, 201])) {
            return new Result(code: 505, message: $client->getBody());
        }
        $json = json_decode($client->getBody(), true);
        if (isset($json['return_code']) && $json['return_code'] != 'SUCCESS') {
            return new Result(code: 500, data: $json['return_msg'] ?? $json['retmsg']);
        } else if ($json['result_code'] != 'SUCCESS') {
            return new Result(code: 500, data: $this->_errors[$json['err_code']] ?? $json['err_code_desc']);
        } else {
            return new Result(code: 0, data: $json);
        }
    }

    /**
     * @param string $mch_billno
     * @param string $openId
     * @param float $price
     * @return array
     */
    private function orderConfig(string $mch_billno, string $openId, float $price): array
    {
        $requestParam['input_charset']    = 'UTF-8';
        $requestParam['nonce_str']        = Help::random(32);
        $requestParam['out_trade_no']     = $mch_billno;
        $requestParam['mch_id']           = $this->payConfig->pay->qq->mchId;
        $requestParam['appid']            = $this->payConfig->pay->qq->mchSecret;
        $requestParam['openid']           = $openId;
        $requestParam['fee_type']         = 'CNY';
        $requestParam['total_fee']        = $price * 100;
        $requestParam['memo']             = $this->payConfig->getBody();
        $requestParam['notify_url']       = $this->payConfig->getNotifyUrl();
        $requestParam['spbill_create_ip'] = $this->payConfig->getNotifyUrl();
        if (!empty($this->_requestParams) && is_array($this->_requestParams)) {
            $requestParam = array_merge($requestParam, $this->_requestParams);
        }
        $requestParam['sign'] = Help::sign($requestParam, $this->payConfig->pay->qq->mchSecret, 'MD5');
        return $requestParam;
    }


    /**
     * @return string
     * @throws Exception
     */
    public function mchOrderNo(): string
    {
        return implode([
            $this->payConfig->pay->qq->mchId,
            date('Ymd'),
            random_int(11, 99),
            date('His'),
            random_int(11, 99)
        ]);
    }


    /**
     * @param array $requestParams
     * @return bool
     */
    public function validator(array $requestParams): bool
    {
        $notifySign = $requestParams['sign'];
        unset($requestParams['sign']);
        $sign = Help::sign($requestParams, $this->payConfig->pay->qq->mchSecret, 'MD5');

        if ($sign !== $notifySign) {
            return false;
        }

        return true;
    }

}
